﻿using UnityEngine;
using UnityEditor;
using System.Collections;
using UnityEditor.Animations;
using System.Collections.Generic;
using UnityEngine.Rendering;
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;
using Newtonsoft.Json;

public static class ShaderTool
{
    static string shaderDir = ResourcesEx.BundleResDir + "/shader";
    static string shaderVariantMatDir = ResourcesEx.BundleResDir + "/shader/" + "shader_variant";
    public static string assetBundleShaderVariantMatDir = shaderVariantMatDir;

    [MenuItem("Assets/Custom/ShaderTool/SetMaterialRenderQueueFromShader")]
    public static void SetMaterialRenderQueueFromShader()
    {
        HashSet<string> pathSet = new HashSet<string>();
        EditorCommonTool.ProcessSelectionObjs("*.mat", (path) => 
            {
                Material mat = AssetDatabase.LoadAssetAtPath<Material>(path);
                if(mat != null)
                {
                    if(mat.enableInstancing)
                    {
                        mat.enableInstancing = false;
                    }

//                    if(mat.renderQueue != -1)
//                    {
//                        pathSet.Add(path);
//                        mat.renderQueue = -1;
//                    }
//                    mat.renderQueue = (int)RenderQueue.Transparent;
                }
            });

        AssetDatabase.SaveAssets();

        string log = "";
        foreach(var path in pathSet)
        {
            log += path + "\n";
        }


        Debug.LogError(log);
    }

    [MenuItem("Assets/Custom/ShaderTool/FindAllShaderOfMaterial")]
    public static void FindAllShaderOfMaterial()
    {
        HashSet<string> pathSet = new HashSet<string>();
        EditorCommonTool.ProcessSelectionObjs("*.mat", (path) => 
            {
                Material mat = AssetDatabase.LoadAssetAtPath<Material>(path);
                string shaderPath = AssetDatabase.GetAssetPath(mat.shader);
                pathSet.Add(shaderPath);
            });

        string log = "";
        foreach(var path in pathSet)
        {
            log += path + "\n";
        }

        Debug.LogError(log);
    }

	[MenuItem("Assets/Custom/ShaderTool/TestCubemap")]
	public static void TestCubemap()
	{
		if (Selection.activeObject is Cubemap)
		{
			Color color = Color.black;
			int num = 0;
			Cubemap c = Selection.activeObject as Cubemap;
			CubemapFace[] cubemapFaces = new CubemapFace[]{ CubemapFace.PositiveZ, CubemapFace.NegativeZ, CubemapFace.NegativeX, CubemapFace.PositiveX, CubemapFace.PositiveY, CubemapFace.NegativeY };
			for (int i = 0; i < cubemapFaces.Length; i++)
			{
				Color[] pixels = c.GetPixels(cubemapFaces[i]);
				for (int j = 0; j < pixels.Length; j++)
				{
					Color temp = pixels[j];
					if (temp.r + temp.g + temp.b > color.r + color.g + color.b)
					{
						color = temp;
					}

					if (temp.maxColorComponent  < 0.5)
					{
						num++;
					}
				}
			}

			Debug.LogError("test_color: " + color + "  " + num);
		}

		if (Selection.activeObject is Texture2D)
		{
			Color32 color = new Color32();
			Texture2D c = Selection.activeObject as Texture2D;
			Color32[] pixels = c.GetPixels32();
			for (int j = 0; j < pixels.Length; j++)
			{
				Color temp = pixels[j];
				if (1 * (temp.r + temp.g + temp.b) > 1 * (color.r + color.g + color.b))
				{
					color = temp;
				}
			}

			Debug.LogError("test_color: " + color);
		}




//		string texPath = AssetDatabase.GetAssetPath(Selection.activeObject);
//		TextureImporter importer = TextureImporter.GetAtPath(texPath) as TextureImporter;
//		importer.textureShape = TextureImporterShape.Texture2D;
//		importer.SaveAndReimport();
//
//		Texture2D tex = AssetDatabase.LoadAssetAtPath<Texture2D>(texPath);

//		Cubemap c = Selection.activeObject as Cubemap;
//		CubemapFace[] cubemapFaces = new CubemapFace[]{CubemapFace.PositiveZ, CubemapFace.NegativeZ, CubemapFace.NegativeX, CubemapFace.PositiveX, CubemapFace.PositiveY, CubemapFace.NegativeY};
//		for(int i = 0; i < cubemapFaces.Length; i++)
//		{
//			Color[] pixels = c.GetPixels(cubemapFaces[i]);
//			for(int j = 0; j < pixels.Length; j++)
//			{
//				pixels[j] = Color.white;
//			}
//
//			c.SetPixels(pixels, cubemapFaces[i]);
//		}
	}

    [MenuItem("Assets/Custom/ShaderTool/ConvertMetalTexToSpecTex")]
    public static void ConvertMetalTexToSpecTex()
    {
        HashSet<string> s = new HashSet<string>();
        EditorCommonTool.ProcessSelectionObjs("*.mat", (path) =>
            {
                Material mat = AssetDatabase.LoadAssetAtPath<Material>(path);
                if(mat == null)
                {
                    return;
                }

                Shader shader = mat.shader;
                if(shader == null)
                {
                    return;
                }

                if(shader.name.Contains("Standard") && !shader.name.Contains("(Specular setup)"))
                {
                    Texture2D glossMap = mat.GetTexture("_MetallicGlossMap") as Texture2D;
                    if(glossMap != null)
                    {
                        string texPath = AssetDatabase.GetAssetPath(glossMap);
                        if(s.Contains(texPath))
                        {
                            return;
                        }

                        s.Add(texPath);
                        string newTexPath = ConvertToSpecTex(texPath);
                        s.Add(newTexPath);
                    }
                }
            });

        AssetDatabase.Refresh();
        AssetDatabase.SaveAssets();
    }

    public static string ConvertToSpecTex(string texPath)
    {
        string oldMetaFilePath = texPath + ".meta";
        string metaContent = CommonUtil.fileToString(oldMetaFilePath);
        Dictionary<string,TempTextureFormat> temp = MaterialTextureForETC1.SetTextureReadable(texPath);
        Texture2D tex = AssetDatabase.LoadAssetAtPath(texPath, typeof(Texture2D)) as Texture2D;
        if (tex == null)
        {
            return null;
        }

        int sum = 0;

        Color[] colorData = tex.GetPixels();
        for (int i = 0; i < colorData.Length; i++)
        {
            if (colorData[i].g > 0.3f || colorData[i].b > 0.3f)
            {
                sum++;
                if (sum >= tex.width)
                {
                    MaterialTextureForETC1.ReverseTextureReadable(texPath, temp);
                    CommonUtil.stringToFile(oldMetaFilePath, metaContent);
                    Resources.UnloadAsset(tex);
                    return null;
                }
            }

            colorData[i].g = colorData[i].r;
            colorData[i].b = colorData[i].r;
        }
        tex.SetPixels(colorData);

        byte[] data = tex.EncodeToPNG();
        Resources.UnloadAsset(tex);

        MaterialTextureForETC1.ReverseTextureReadable(texPath, temp);
        CommonUtil.stringToFile(oldMetaFilePath, metaContent);

        string newPath = System.IO.Path.ChangeExtension(texPath, ".png");
        CommonUtil.bytesToFile(newPath, data);

        if (newPath != texPath)
        {
            string newMetaFilePath = newPath + ".meta";
            CommonUtil.Move(oldMetaFilePath, newMetaFilePath);
            CommonUtil.Delete(texPath);
        }

        return newPath;
    }


    [MenuItem("Assets/Custom/ShaderTool/MaxSpecular")]
    public static void MaxSpecular()
    {
        EditorCommonTool.ProcessSelectionObjs("*.mat", (path) =>
            {
                Material mat = AssetDatabase.LoadAssetAtPath<Material>(path);
                if(mat == null)
                {
                    return;
                }

                Shader shader = mat.shader;
                if(shader == null)
                {
                    return;
                }

                if(shader.name.Contains("Bumped Specular IBL"))
                {
                    mat.SetFloat("_Shininess", 8);
                    mat.SetColor("_SpecColor", Color.white);
                }
            });

        AssetDatabase.Refresh();
        AssetDatabase.SaveAssets();
    }

    [MenuItem("Assets/Custom/ShaderTool/ConvertToStandardSpecularShader")]
    public static void ConvertToStandardSpecularShader()
    {
        HashSet<string> foundSet = new HashSet<string>();
        EditorCommonTool.ProcessSelectionObjs("*.mat", (path) =>
            {
//                if(path.Contains("Assets/art/model/bone/bone709/Materials/bone117_mat1.mat"))
//                {
//                    Debug.LogError("a");
//                }

                Material mat = AssetDatabase.LoadAssetAtPath<Material>(path);
                if(mat == null)
                {
                    return;
                }

                Shader shader = mat.shader;
                if(shader == null)
                {
                    return;
                }

                string shaderName = shader.name;
                if(shaderName.Contains("Standard") && !shaderName.Contains("Specular"))
                {
                    string newShaderName = shaderName.Replace("Standard", "Standard (Specular setup)");
                    if(newShaderName == "Standard (Specular setup)")
                    {
                        newShaderName = "custom/" + newShaderName + "-New";
                    }

                    Shader newShader = Shader.Find(newShaderName);
                    if(newShader != null)
                    {
                        mat.shader = newShader;
                    }
                    else
                    {
                        foundSet.Add(path);
                    }
                }
                else if(shaderName == "Standard (Specular setup)")
                {
                    string newShaderName = "custom/" + shaderName + "-New";
                    Shader newShader = Shader.Find(newShaderName);
                    if(newShader != null)
                    {
                        Texture tex = mat.GetTexture("_MetallicGlossMap");
                        mat.shader = newShader;
                        mat.SetTexture("_SpecGlossMap", tex);
                    }
                    else
                    {
                        foundSet.Add(path);
                    }
                }
            });

        string log = "";
        foreach (var s in foundSet)
        {
            log += s + "\n";
        }
        if (!string.IsNullOrEmpty(log))
        {
            Debug.LogError(log);
        }

        AssetDatabase.Refresh();
        AssetDatabase.SaveAssets();
    }

    [MenuItem("Assets/Custom/ShaderTool/CountStandardSpecularShaderVariant")]
    public static void CountStandardSpecularShaderVariant()
    {
        HashSet<string> foundSet = new HashSet<string>();
        EditorCommonTool.ProcessSelectionObjs("*.mat", (path) =>
            {
                Material mat = AssetDatabase.LoadAssetAtPath<Material>(path);
                if(mat == null)
                {
                    return;
                }

                Shader shader = mat.shader;
                if(shader == null)
                {
                    return;
                }

                string shaderName = shader.name;
                if(shaderName == "custom/Standard (Specular setup)-New")
                {
                    List<string> keys = new List<string>(mat.shaderKeywords);
                    keys.Sort();
                    string keyWordStr = string.Concat(keys.ToArray());
                    foundSet.Add(keyWordStr);
                }
            });

        string log = "CountStandardSpecularShader:" + foundSet.Count + "\n";
        foreach (var s in foundSet)
        {
            log += s + "\n";
        }
        if (!string.IsNullOrEmpty(log))
        {
            Debug.LogError(log);
        }

        AssetDatabase.Refresh();
        AssetDatabase.SaveAssets();
    }

//    [MenuItem("Assets/Custom/ShaderTool/ConvertSlice6SkyBoxToCubeMap")]
//    public static void ConvertSlice6SkyBoxToCubeMap()
//    {
//        Material mat = Selection.activeObject as Material;
//        string[] texNames = new string[]{"_FrontTex", "_BackTex", "_LeftTex", "_RightTex", "_UpTex", "_DownTex"};
//        CubemapFace[] cubemapFaces = new CubemapFace[]{CubemapFace.PositiveZ, CubemapFace.NegativeZ, CubemapFace.NegativeX, CubemapFace.PositiveX, CubemapFace.PositiveY, CubemapFace.NegativeY};
//
//        Texture2D firstTex = mat.GetTexture(texNames[0]) as Texture2D;
//        Cubemap cubeMap = new Cubemap(firstTex.width, TextureFormat.RGB9e5Float, true);
//        for (int i = 0; i < texNames.Length; i++)
//        {
//            Texture2D sliceTex = mat.GetTexture(texNames[i]) as Texture2D;
//            string sliceTexPath = AssetDatabase.GetAssetPath(sliceTex);
//            Dictionary<string, TempTextureFormat> dic = MaterialTextureForETC1.SetTextureReadable(sliceTexPath);
//            sliceTex = AssetDatabase.LoadAssetAtPath<Texture2D>(sliceTexPath);
//            cubeMap.SetPixels(sliceTex.GetPixels(), cubemapFaces[i]);
//            MaterialTextureForETC1.ReverseTextureReadable(sliceTexPath, dic);
//        }
//
//        string texPath = AssetDatabase.GetAssetPath(firstTex);
//        string matPath = AssetDatabase.GetAssetPath(mat);
//        string cubemapPath = matPath.Replace(".mat", "_cubemap.cubemap");
//
//        AssetDatabase.CreateAsset(cubeMap, cubemapPath);
//    }

//    [MenuItem("Assets/Custom/ShaderTool/ConvertSlice6SkyBoxToCubeMap")]
//    public static void ConvertSlice6SkyBoxToCubeMap()
//    {
//        Material mat = Selection.activeObject as Material;
//        string[] texNames = new string[]{"_FrontTex", "_BackTex", "_LeftTex", "_RightTex", "_UpTex", "_DownTex"};
//        CubemapFace[] cubemapFaces = new CubemapFace[]{CubemapFace.PositiveZ, CubemapFace.NegativeZ, CubemapFace.NegativeX, CubemapFace.PositiveX, CubemapFace.PositiveY, CubemapFace.NegativeY};
//
//        Texture2D cubeMap = null;
//        for (int i = 0; i < texNames.Length; i++)
//        {
//            Texture2D sliceTex = mat.GetTexture(texNames[i]) as Texture2D;
//            string sliceTexPath = AssetDatabase.GetAssetPath(sliceTex);
//            Dictionary<string, TempTextureFormat> dic = MaterialTextureForETC1.SetTextureReadable(sliceTexPath);
//            sliceTex = AssetDatabase.LoadAssetAtPath<Texture2D>(sliceTexPath);
//            if(cubeMap == null)
//            {
//                cubeMap = new Texture2D(sliceTex.width * 6, sliceTex.width, TextureFormat.RGBAFloat, true);
//            }
//            cubeMap.SetPixels32(i * sliceTex.width, 0, sliceTex.width, sliceTex.height, sliceTex.GetPixels32());
//            MaterialTextureForETC1.ReverseTextureReadable(sliceTexPath, dic);
//        }
//
//        byte[] data = cubeMap.EncodeToPNG();
//        string matPath = AssetDatabase.GetAssetPath(mat);
//        string cubemapPath = matPath.Replace(".mat", "_cubemap.png");
//
//        CommonUtil.bytesToFile(cubemapPath, data);
//
//        AssetDatabase.Refresh();
//    }

    [MenuItem("Assets/Custom/ShaderTool/ConvertSlice6SkyBoxToCubeMap")]
    public static string ConvertSlice6SkyBoxToCubeMap()
    {
        Material mat = Selection.activeObject as Material;

        Scene oldScene = EditorSceneManager.GetActiveScene();
        string oldScenePath = oldScene.path;
        Scene scene = EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects);
        string scenePath = "Assets/testtest";
        EditorSceneManager.SaveScene(scene, scenePath + ".unity");
        scene = EditorSceneManager.OpenScene(scenePath + ".unity");
        string cubeScenePath = scene.path;

        AssetDatabase.Refresh();

        Lightmapping.giWorkflowMode = Lightmapping.GIWorkflowMode.OnDemand;
        Lightmapping.realtimeGI = false;
        RenderSettings.skybox = mat;
        RenderSettings.defaultReflectionResolution = 512;
        Lightmapping.Bake();

        AssetDatabase.Refresh();

        string matPath = AssetDatabase.GetAssetPath(mat);
        EditorSceneManager.OpenScene(oldScenePath);
        AssetDatabase.DeleteAsset(scenePath + ".unity");

        string exrPath = matPath.Replace(".mat", "_cubemap.exr");
        AssetDatabase.MoveAsset(scenePath + "/ReflectionProbe-0.exr", exrPath);
        CommonUtil.Delete(scenePath);

        AssetDatabase.Refresh();

        return exrPath;
    }

    [MenuItem("Assets/Custom/ShaderTool/ConvertToNewSkyBoxMaterial")]
    public static void ConvertToNewSkyBoxMaterial()
    {
        Material mat = Selection.activeObject as Material;
        string cubeMapPath = ConvertSlice6SkyBoxToCubeMap();
        mat.shader = Shader.Find("custom/Skybox/Cubemap-New");
        mat.SetTexture("_Tex", AssetDatabase.LoadAssetAtPath<Cubemap>(cubeMapPath));
    }

    [MenuItem("Custom/ShaderTool/PrintRenderQueue")]
    public static void PrintRenderQueue()
    {
        Debug.LogError("Geometry:" + (int)UnityEngine.Rendering.RenderQueue.Geometry);
        Debug.LogError("AlphaTest:" + (int)UnityEngine.Rendering.RenderQueue.AlphaTest);
        Debug.LogError("Background:" + (int)UnityEngine.Rendering.RenderQueue.Background);
        Debug.LogError("GeometryLast:" + (int)UnityEngine.Rendering.RenderQueue.GeometryLast);
        Debug.LogError("Overlay:" + (int)UnityEngine.Rendering.RenderQueue.Overlay);
        Debug.LogError("Transparent:" + (int)UnityEngine.Rendering.RenderQueue.Transparent);
    }

    [MenuItem("Custom/ShaderTool/ConvertToNewStandardShader")]
    public static void ConvertToNewStandardShader()
    {
        Shader standardShader = Shader.Find("Standard");
        Shader standardSpecularShader = Shader.Find("Standard (Specular setup)");
        Shader newStandardShader = Shader.Find("custom/Standard-New");
        Shader newStandardSpecularShader = Shader.Find("custom/Standard (Specular setup)-New");

        string[] paths = System.IO.Directory.GetFiles(ResourcesEx.BundleResDir, "*.mat", System.IO.SearchOption.AllDirectories);
        for (int i = 0; i < paths.Length; i++)
        {
            Material mat = AssetDatabase.LoadAssetAtPath<Material>(paths[i]);
            if (mat.shader == standardShader)
            {
                mat.shader = newStandardShader;
            }
            if (mat.shader == standardSpecularShader)
            {
                mat.shader = newStandardSpecularShader;
            }
        }

        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }

    [MenuItem("Assets/Custom/ShaderTool/CountMetalTex")]
    public static void CountMetalTex()
    {
        Dictionary<string, string> dic = new Dictionary<string, string>();
        EditorCommonTool.ProcessSelectionObjs("*.mat", (path) =>
            {
                Material mat = AssetDatabase.LoadAssetAtPath<Material>(path);
                if(mat == null)
                {
                    return;
                }

                Shader shader = mat.shader;
                if(shader == null)
                {
                    return;
                }

                if(shader.name.Contains("Standard") && !shader.name.Contains("Specular"))
                {
                    if(mat.HasProperty("_MetallicGlossMap"))
                    {
                        Texture tex = mat.GetTexture("_MetallicGlossMap");
                        if(tex != null)
                        {
                            string texPath = AssetDatabase.GetAssetPath(tex);
                            dic.Add(path, texPath);
                        }
                    }
                }
            });

        string str = JsonConvert.SerializeObject(dic, Formatting.Indented);

        CommonUtil.stringToFile("metal_tex.json", str);
    }

    [MenuItem("Assets/Custom/ShaderTool/SetSpecularShaderSpecGlossMap")]
    public static void SetSpecularShaderSpecGlossMap()
    {
        string str = CommonUtil.fileToString("metal_tex.json");
        Dictionary<string, string> dic = JsonConvert.DeserializeObject<Dictionary<string, string>>(str);
        EditorCommonTool.ProcessSelectionObjs("*.mat", (path) =>
            {
                string texPath = null;
                if(!dic.TryGetValue(path, out texPath))
                {
                    return;
                }

                Material mat = AssetDatabase.LoadAssetAtPath<Material>(path);
                if(mat == null)
                {
                    return;
                }

                Shader shader = mat.shader;
                if(shader == null)
                {
                    return;
                }

                Texture2D tex = AssetDatabase.LoadAssetAtPath<Texture2D>(texPath);
                mat.SetTexture("_SpecGlossMap", tex);
            });

        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }

    [MenuItem("Assets/Custom/ShaderTool/ResetSpecularMaterialKeywords")]
    public static void ResetSpecularMaterialKeywords()
    {
        HashSet<string> kwSet = new HashSet<string>();
        kwSet.Add("_ALPHATEST_ON");
        kwSet.Add("_ALPHAPREMULTIPLY_ON");
        kwSet.Add("_ALPHABLEND_ON");
        kwSet.Add("_EMISSION");
        kwSet.Add("_NORMALMAP");
        kwSet.Add("_SPECGLOSSMAP");

        EditorCommonTool.ProcessSelectionObjs("*.mat", (path) =>
            {
                Material mat = AssetDatabase.LoadAssetAtPath<Material>(path);
                if(mat == null)
                {
                    return;
                }

                Shader shader = mat.shader;
                if(shader == null)
                {
                    return;
                }

                if(shader.name.Contains("Standard") && shader.name.Contains("Specular"))
                {
                    string[] kws = mat.shaderKeywords;
                    List<string> kwList = new List<string>();
                    for(int i = 0; i < kws.Length; i++)
                    {
                        if(kwSet.Contains(kws[i]))
                        {
                            kwList.Add(kws[i]); 
                        }
                    }

                    mat.shaderKeywords = kwList.ToArray();
                }
            });

        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }

    static void ForeachKey(Material mat, List<string[]> keysList, int listIndex, string[] selectedKeys, string outputPath)
    {
        if (listIndex >= keysList.Count)
        {
            bool found = false;
            for (int i = 0; i < selectedKeys.Length; i++)
            {
                if (selectedKeys[i] != null)
                {
                    found = true;
                }
            }

            if (found)
            {
                Material newMat = new Material(mat);
                for (int i = 0; i < selectedKeys.Length; i++)
                {
                    if (selectedKeys[i] != null)
                    {
                        newMat.EnableKeyword(selectedKeys[i]);
                    }
                }

                CreateShaderVariant(newMat, null, false, outputPath);
                CreateShaderVariant(newMat, null, true, outputPath);
            }
            return;
        }

        string[] keys = keysList[listIndex];
        for (int i = 0; i < keys.Length + 1; i++)
        {
            if (i > 0)
            {
                selectedKeys[listIndex] = keys[i - 1];
            }
            else
            {
                selectedKeys[listIndex] = null;
            }

            ForeachKey(mat, keysList, listIndex + 1, selectedKeys, outputPath);
        }
    }

    static string KeysToString(string[] keys, bool isInstancing)
    {
        if (keys.Length <= 0)
        {
            return null;
        }

        List<string> keyList = new List<string>(keys);
        keyList.Sort();
        string keyWordStr = string.Concat(keyList.ToArray());
        if (isInstancing)
        {
            keyWordStr = "_instancing_" + keyWordStr;
        }
        return keyWordStr;
    }

    public static void CreateShaderVariant(Material mat, Shader shader, bool isInstancing, string matDir)
    {
        string keyWordStr = KeysToString(mat.shaderKeywords, isInstancing);
        if (string.IsNullOrEmpty(keyWordStr))
        {
            return;
        }

        CommonUtil.CreateDir(matDir);

        shader = shader ?? mat.shader;

        string shaderPath = AssetDatabase.GetAssetPath(shader);
        if (!shaderPath.StartsWith(shaderDir))
        {
            return;
        }

        string shaderFileName = System.IO.Path.GetFileNameWithoutExtension(shaderPath);
        string matName = shaderFileName + keyWordStr;
//        newMaterial.name = matName;
        string matPath = matDir + "/" + matName + ".mat";
        if (System.IO.File.Exists(matPath))
        {
            return;
        }




        Material newMat = new Material(shader);
        newMat.shaderKeywords = mat.shaderKeywords;
        newMat.enableInstancing = isInstancing;

//        int propCount = ShaderUtil.GetPropertyCount(shader);
//        for (int i = 0; i < propCount; i++)
//        {
//            ShaderUtil.ShaderPropertyType propType = ShaderUtil.GetPropertyType(shader, i);
//            if (propType == ShaderUtil.ShaderPropertyType.TexEnv)
//            {
//                string propName = ShaderUtil.GetPropertyName(shader, i);
//                Texture2D tex = mat.GetTexture(propName) as Texture2D;
//                if (tex != null)
//                {
//                    Texture newTex = AssetDatabase.LoadAssetAtPath<Texture>(ResourcesEx.BundleResDir + "/shader/for_variant.png");
////                    Texture newTex = null;
//                    newMat.SetTexture(propName, newTex);
//                }
//            }
//        }

        AssetDatabase.CreateAsset(newMat, matPath);
    }



    [MenuItem("Custom/ShaderTool/BuildShaderVariantCollection")]
    public static void BuildShaderVariantCollection()
    {
//        ShaderVariantCollection svc = AssetDatabase.LoadAssetAtPath<ShaderVariantCollection>(ResourcesEx.BundleResDir + "/shader/shader_variants.shadervariants");
//        bool isNew = false;
//        if (svc == null)
//        {
//            svc = new ShaderVariantCollection();
//            isNew = true;
//        }
//        svc.Clear();
//        if (isNew)
//        {
//            AssetDatabase.CreateAsset(svc, ResourcesEx.BundleResDir + "/shader/shader_variants.shadervariants");
//        }
//        else
//        {
//            AssetDatabase.SaveAssets();
//        }

		
		string artPath = "Assets/art";
        {

            List<KeyValuePair<string, List<Shader>>> list = new List<KeyValuePair<string, List<Shader>>>();
            {
                List<Shader> shaders = new List<Shader>();
//            shaders.Add(Shader.Find("custom/Standard (Specular setup)-New-Avatar"));
                shaders.Add(Shader.Find("custom/Standard (Specular setup)-New-NormalEdge"));
                list.Add(new KeyValuePair<string, List<Shader>>("Standard (Specular setup)", shaders));
            }

//        {
//            List<Shader> shaders = new List<Shader>();
////            shaders.Add(Shader.Find("custom/Standard-New-Avatar"));
//            shaders.Add(Shader.Find("custom/Standard-New-NormalEdge"));
//            list.Add(new KeyValuePair<string, List<Shader>>("Standard", shaders));
//        }

            if (System.IO.Directory.Exists(shaderVariantMatDir))
            {
                System.IO.Directory.Delete(shaderVariantMatDir, true);
            }

            System.IO.Directory.CreateDirectory(shaderVariantMatDir);

            Dictionary<string, HashSet<string>> searchedSetMap = new Dictionary<string, HashSet<string>>();

            HashSet<string> foundShaders = new HashSet<string>();

            HashSet<string> addedShaders = new HashSet<string>();
			
			
			if(CommonUtil.Exists(artPath))
			{
				string[] paths = System.IO.Directory.GetFiles(artPath, "*.mat", System.IO.SearchOption.AllDirectories);
				for (int i = 0; i < paths.Length; i++)
				{
					Material mat = AssetDatabase.LoadAssetAtPath<Material>(paths[i]);

					for (int j = 0; j < list.Count; j++)
					{
						KeyValuePair<string, List<Shader>> entry = list[j];
						if (mat != null && mat.shader != null && mat.shader.name.Contains(entry.Key))
						{
							addedShaders.Add(mat.shader.name);
							for (int k = 0; k < entry.Value.Count; k++)
							{
								string[] keywords = mat.shaderKeywords;
								if (keywords == null || keywords.Length <= 0)
								{
									continue;
								}

								HashSet<string> searchSet = null;
								if (!searchedSetMap.TryGetValue(entry.Value[k].name, out searchSet))
								{
									searchSet = new HashSet<string>();
									searchedSetMap.Add(entry.Value[k].name, searchSet);
								}

								string keyStr = KeysToString(mat.shaderKeywords, false);
								if (searchSet.Contains(keyStr))
								{
									continue;
								}
								searchSet.Add(keyStr);

								CreateShaderVariant(mat, entry.Value[k], false, shaderVariantMatDir);
								CreateShaderVariant(mat, entry.Value[k], true, shaderVariantMatDir);
							}

							break;
						}
					}
				}
			}
            string log = "";
            foreach (var s in foundShaders)
            {
                log += s + "\n";
            }

            if (!string.IsNullOrEmpty(log))
            {
                Debug.LogError(log);
            }

            AssetDatabase.Refresh();
            AssetDatabase.SaveAssets();
        }

        {
            
            Dictionary<string, List<string[]>> shaderFeatureKeyMap = new Dictionary<string, List<string[]>>();
            {
                string[] keys = new string[]{ "_HIT_EFFECT", "_FLOW_EFFECT" };
                List<string[]> keysList = new List<string[]>();
                keysList.Add(keys);
                shaderFeatureKeyMap.Add("custom/Standard (Specular setup)-New", keysList);
            }

            {
                string[] keys = new string[]{ "_HIT_EFFECT" };
                List<string[]> keysList = new List<string[]>();
                keysList.Add(keys);
                shaderFeatureKeyMap.Add("custom/Standard (Specular setup)-New-NormalEdge", keysList);
            }


            List<string> matPaths = new List<string>();
			
			string[] dirs = new string[]{ artPath, shaderVariantMatDir };
            for (int i = 0; i < dirs.Length; i++)
            {
                string dir = dirs[i];
				if(CommonUtil.Exists(dir))
				{
					string[] paths = System.IO.Directory.GetFiles(dir, "*.mat", System.IO.SearchOption.AllDirectories);
					matPaths.AddRange(paths);
				}
            }

            Dictionary<string, HashSet<string>> searchedSetMap = new Dictionary<string, HashSet<string>>();
            for (int j = 0; j < matPaths.Count; j++)
            {
                string matPath = matPaths[j];
                Material mat = AssetDatabase.LoadAssetAtPath<Material>(matPath);
                if (mat == null || mat.shader == null)
                {
                    continue;
                }

                HashSet<string> searchSet = null;
                if (!searchedSetMap.TryGetValue(mat.shader.name, out searchSet))
                {
                    searchSet = new HashSet<string>();
                    searchedSetMap.Add(mat.shader.name, searchSet);
                }

                string keyStr = KeysToString(mat.shaderKeywords, false);
                if (searchSet.Contains(keyStr))
                {
                    continue;
                }
                searchSet.Add(keyStr);

                List<string[]> keysList = null;
                if (shaderFeatureKeyMap.TryGetValue(mat.shader.name, out keysList))
                {
                    string[] selectedKeys = new string[keysList.Count];
                    ForeachKey(mat, keysList, 0, selectedKeys, shaderVariantMatDir);
                }
            }
        }

        //        HashSet<string>.Enumerator e = addedShaders.GetEnumerator();
        //        while (e.MoveNext())
        //        {
        //            Debug.LogError(e.Current);
        //        }




//        ShaderVariantCollection svc = AssetDatabase.LoadAssetAtPath<ShaderVariantCollection>(ResourcesEx.BundleResDir + "/shader/shader_variants.shadervariants");
//        bool isNew = false;
//        if (svc == null)
//        {
//            svc = new ShaderVariantCollection();
//            isNew = true;
//        }
//        svc.Clear();
//
//        List<KeyValuePair<string, List<Shader>>> list = new List<KeyValuePair<string, List<Shader>>>();
//        {
//            List<Shader> shaders = new List<Shader>();
//            shaders.Add(Shader.Find("custom/Standard (Specular setup)-New-Avatar"));
//            shaders.Add(Shader.Find("custom/Standard (Specular setup)-New-NormalEdge"));
//            list.Add(new KeyValuePair<string, List<Shader>>("Standard (Specular setup)", shaders));
//        }
//
//        {
//            List<Shader> shaders = new List<Shader>();
//            shaders.Add(Shader.Find("custom/Standard-New-Avatar"));
//            shaders.Add(Shader.Find("custom/Standard-New-NormalEdge"));
//            list.Add(new KeyValuePair<string, List<Shader>>("Standard", shaders));
//        }
//
//        HashSet<string> addedShaders = new HashSet<string>();
//        string[] paths = System.IO.Directory.GetFiles(ResourcesEx.BundleResDir, "*.mat", System.IO.SearchOption.AllDirectories);
//        for (int i = 0; i < paths.Length; i++)
//        {
//            Material mat = AssetDatabase.LoadAssetAtPath<Material>(paths[i]);
//
//            for (int j = 0; j < list.Count; j++)
//            {
//                KeyValuePair<string, List<Shader>> entry = list[j];
//                if (mat.shader.name == (entry.Key))
//                {
//                    addedShaders.Add(mat.shader.name);
//                    for (int k = 0; k < entry.Value.Count; k++)
//                    {
//                        bool needAdd = false;
//                        if (mat.shaderKeywords.Length > 1)
//                        {
//                            needAdd = true;
//                        }
//
//                        if (!needAdd)
//                        {
//                            continue;
//                        }
//
//                        ShaderVariantCollection.ShaderVariant v = new ShaderVariantCollection.ShaderVariant();
//                        string[] keywords = new string[mat.shaderKeywords.Length + 1];
//                        mat.shaderKeywords.CopyTo(keywords, 1);
//                        keywords[0] = "DIRECTIONAL";
//                        v.keywords = keywords;
//                        v.shader = entry.Value[k];
//                        v.passType = UnityEngine.Rendering.PassType.ForwardBase;
//                        if (!svc.Contains(v))
//                        {
//                            svc.Add(v);
//                        }
//                        else
//                        {
////                            string log = v.shader.name + "[";
////                            for(int u = 0; u < v.keywords.Length; u++)
////                            {
////                                log += v.keywords[u];
////                                if (u < v.keywords.Length - 1)
////                                {
////                                    log += ",";
////                                }
////                            }
////                            log += "]";
////                            Debug.LogError("shader variant repeat: " + log);
//                        }
//                    }
//                }
//            }
//        }
//
////        HashSet<string>.Enumerator e = addedShaders.GetEnumerator();
////        while (e.MoveNext())
////        {
////            Debug.LogError(e.Current);
////        }
//
//        if (isNew)
//        {
//            AssetDatabase.CreateAsset(svc, ResourcesEx.BundleResDir + "/shader/shader_variants.shadervariants");
//        }
//        else
//        {
//            AssetDatabase.SaveAssets();
//        }
    }


}